package services;

import org.springframework.transaction.annotation.Transactional;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.Session;
import data.*;

import java.util.List;

// This class is the business services tier in the application.
// @Transactional is needed so that a Hibernate transaction is set up,
//  otherwise updates won't have an affect
@Transactional
public class Services {
	// So Spring can inject the session factory
	SessionFactory sessionFactory;

	public void setSessionFactory(SessionFactory value) {
		sessionFactory = value;
	}

	// Shortcut for sessionFactory.getCurrentSession()
	public Session sess() {
		return sessionFactory.getCurrentSession();
	}

	/**
	 * Gets the account by id.
	 * 
	 * @param id
	 *            the id
	 * @return the account by id
	 */
	public Account getAccountByID(int id) {
		return (Account) sess().load(Account.class, id);
	}

	/**
	 * Gets the staff by id.
	 * 
	 * @param id
	 *            the id
	 * @return the staff by id
	 */
	public Staff getStaffByID(int id) {
		return (Staff) sess().load(Staff.class, id);
	}

	/**
	 * Gets the staff id by email.
	 * 
	 * @param email
	 *            the email
	 * @return the staff id by email
	 */
	public int getStaffIDByEmail(String email) {
		Query query = sess().createQuery(
				"from Staff where staffEmail = :staffEmail");
		query.setString("staffEmail", email);
		Staff staff = (Staff) query.uniqueResult();
		return staff.getStaffId();
	}

	/**
	 * Gets the staffs.
	 * 
	 * @return the staffs
	 */
	@SuppressWarnings("unchecked")
	public List<Staff> getStaffs() {
		return sess().createQuery("from Staff").list();
	}

	/**
	 * Gets the complaints.
	 * 
	 * @return the complaints
	 */
	@SuppressWarnings("unchecked")
	public List<Complaint> getComplaints() {
		return sess().createQuery("from Complaint where complaintStatus <> 1").list();
	}

	/**
	 * Delete multi staff by ids.
	 * 
	 * @param staffIds
	 *            the staff ids
	 * @return the int
	 */
	public int deleteMultiStaffByIds(String staffIds) {
		try {
			Query query = sess().createQuery(
					"update Staff set staffStatus=0 where staffId in ("
							+ staffIds + ")");
			int result = query.executeUpdate();
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			return -1;
		}
	}

	/**
	 * Delete staff by id.
	 * 
	 * @param id
	 *            the id
	 */
	public void deleteStaffById(int id) {
		Staff staff = getStaffByID(id);
		staff.setStaffStatus(false);
		sess().persist(staff);
	}

	/**
	 * Update account.
	 * 
	 * @param acc
	 *            the acc
	 */
	public void updateAccount(Account acc) {
		Account newAcc = getAccountByID(acc.getAccountId());
		newAcc.setUsername(acc.getUsername());
		newAcc.setPassword(acc.getPassword());
		sess().persist(newAcc);
	}

	/**
	 * Update staff.
	 * 
	 * @param staff
	 *            the staff
	 */
	public void updateStaff(Staff staff) {
		Staff newStaff = getStaffByID(staff.getStaffId());
		newStaff.setStaffName(staff.getStaffName());
		newStaff.setDateJoined(staff.getDateJoined());
		newStaff.setDateLeft(staff.getDateLeft());
		newStaff.setStaffPhone(staff.getStaffPhone());
		newStaff.setStaffEmail(staff.getStaffEmail());
		sess().update(newStaff);
	}

	/**
	 * Gets the account.
	 * 
	 * @param username
	 *            the user name
	 * @param password
	 *            the password
	 * @return the account
	 */
	public Account getAccount(String username, String password) {
		Query query = sess()
				.createQuery(
						"from Account a where a.username = :username and a.password = :password");
		query.setString("username", username);
		query.setString("password", password);
		Account account = (Account) query.uniqueResult();
		return account;
	}

	/**
	 * Creates the complaint.
	 * 
	 * @param complaint
	 *            the complaint
	 */
	public void createComplaint(Complaint complaint) {
		sess().save(complaint);
	}

	/**
	 * Creates the staff.
	 * 
	 * @param staff
	 *            the staff
	 */
	public void createStaff(Staff staff) {
		try {
			sess().save("Staff", staff);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Gets the staff roles.
	 * 
	 * @return the staff roles
	 */
	@SuppressWarnings("unchecked")
	public List<StaffRole> getStaffRoles() {
		return sess().createQuery("from StaffRole").list();
	}

	/**
	 * Gets the departments.
	 * 
	 * @return the departments
	 */
	@SuppressWarnings("unchecked")
	public List<Department> getDepartments() {
		return sess().createQuery("from Department").list();
	}

	/**
	 * Creates the account.
	 * 
	 * @param account
	 *            the account
	 */
	public void createAccount(Account account) {
		account.setAccountRole(new AccountRole(1));
		sess().save(account);
	}

	/**
	 * Delete multi complaint by ids.
	 * 
	 * @param complaintIds
	 *            the complaint ids
	 * @return the int
	 */
	public int deleteMultiComplaintByIds(String complaintIds) {
		try {
			Query query = sess().createQuery(
					"update Complaint set complaintStatus=1 where complaintId in ("
							+ complaintIds + ")");
			int result = query.executeUpdate();
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			return -1;
		}
	}

	/**
	 * Delete complaint by id.
	 * 
	 * @param complaintId
	 *            the complaint id
	 */
	public void deleteComplaintById(int complaintId) {
		Complaint complaint = getComplaintByID(complaintId);
		complaint.setComplaintStatus(new ComplaintStatus(1));
		sess().update(complaint);
	}

	/**
	 * Gets the complaints by id.
	 * 
	 * @param complaintId
	 *            the complaint id
	 * @return the complaints by id
	 */
	public Complaint getComplaintByID(int complaintId) {
		return (Complaint) sess().load(Complaint.class, complaintId);
	}
	
	/**
	 * Gets the technicians.
	 *
	 * @return the technicians
	 */
	@SuppressWarnings("unchecked")
	public List<Staff> getTechnicians() {
		return sess().createQuery("from Staff where staffRole=1").list();
	}


	/**
	 * Assign technicians.
	 *
	 * @param idComplaint the id complaint
	 */
	public void assignTechnicians(int idComplaint, int idTechnician) {
		Complaint complaint = getComplaintByID(idComplaint);
		complaint.setStaff1(new Staff(idTechnician));
		sess().update(complaint);
	}

}
